package com.swt.gap.service.impl;

import com.swt.gap.common.constant.GraphDbConstant;
import com.swt.gap.common.NodeTypeEnum;
import com.swt.gap.common.graph.FulltextIndexCommon;
import com.swt.gap.common.graph.GraphNeo4jVO;
import com.swt.gap.common.graph.GraphProcessor;
import com.swt.gap.config.ServerConfig;
import com.swt.gap.dao.*;
import com.swt.gap.model.entity.*;
import com.swt.gap.model.vo.*;
import com.swt.gap.model.vo.graph.RelationshipBindVO;
import com.swt.gap.model.vo.ontology.OntologyNodeVO;
import com.swt.gap.service.OntologyService;
import com.swt.gap.util.TreeUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

@Service
public class OntologyServiceImpl implements OntologyService {

    public static final String PROPERTY_NAME = "名称";
    public static final String PROPERTY_DESCRIBE = "描述";
    public static final String PROPERTY_STARTTIME = "开始时间";
    public static final String PROPERTY_ENDTIME = "结束时间";
    public static final String PROPERTY_PLACE = "地点";


    private final OntologyMapper ontologyMapper;
    private final OntologyNodeDao ontologyNodeDao;
    private final OntologyNodePropertyDao ontologyNodePropertyDao;
    private final OntologyRelationshipMapper ontologyRelationshipMapper;
    private final OntologyRelationshipPropertyMapper ontologyRelationshipPropertyMapper;
    private final SysIconMapper sysIconMapper;
    private final ServerConfig serverConfig;
    private final GraphProcessor graphProcessor;
    private final FulltextIndexCommon fulltextIndexCommon;

    public OntologyServiceImpl(OntologyMapper ontologyMapper, OntologyNodeDao ontologyNodeDao,
                               OntologyNodePropertyDao ontologyNodePropertyDao,
                               OntologyRelationshipMapper ontologyRelationshipMapper,
                               OntologyRelationshipPropertyMapper ontologyRelationshipPropertyMapper,
                               SysIconMapper sysIconMapper,
                               ServerConfig serverConfig,
                               GraphProcessor graphProcessor,
                               FulltextIndexCommon fulltextIndexCommon) {
        this.ontologyMapper = ontologyMapper;
        this.ontologyNodeDao = ontologyNodeDao;
        this.ontologyNodePropertyDao = ontologyNodePropertyDao;
        this.ontologyRelationshipMapper = ontologyRelationshipMapper;
        this.ontologyRelationshipPropertyMapper = ontologyRelationshipPropertyMapper;
        this.sysIconMapper = sysIconMapper;
        this.serverConfig = serverConfig;
        this.graphProcessor = graphProcessor;
        this.fulltextIndexCommon = fulltextIndexCommon;
    }

    @Override
    public OntologyVO getOntologyById(Integer ontologyId) {
        OntologyVO retValue = new OntologyVO();
        Ontology ontology = ontologyMapper.selectByPrimaryKey(ontologyId);
        BeanUtils.copyProperties(ontology, retValue);

        List<OntologyNodeVO> ontologyEntityList = new ArrayList<>();
        List<OntologyNode> ontologyEntities = ontologyNodeDao.selectByOntologyId(ontologyId);
        ontologyEntities.forEach(ontologyEntity -> {
            OntologyNodeVO oe = new OntologyNodeVO();
            BeanUtils.copyProperties(ontologyEntity, oe);
            oe.setOntologyNodePropertyList(ontologyNodePropertyDao.selectByEntityId(ontologyEntity.getNodeId()));
            ontologyEntityList.add(oe);
        });
        retValue.setOntologyNodeList(ontologyEntityList);

        List<OntologyRelationshipVO> ontologyRelationshipList = new ArrayList<>();
        List<OntologyRelationship> ontologyRelationships = ontologyRelationshipMapper.selectByOntologyId(ontologyId);
        ontologyRelationships.forEach(ontologyRelationship -> {
            OntologyRelationshipVO or = new OntologyRelationshipVO();
            BeanUtils.copyProperties(ontologyRelationship, or);
            or.setOntologyRelationshipPropertyList(ontologyRelationshipPropertyMapper
                    .selectByRelationshipId(ontologyRelationship.getRelationshipId()));
            ontologyRelationshipList.add(or);
        });
        retValue.setOntologyRelationshipList(ontologyRelationshipList);
        return retValue;
    }

    @Override
    public List<OntologyNodeVO> listOntologyEntity() {
        List<OntologyNodeVO> ontologyEntityList = new ArrayList<>();
        List<OntologyNode> ontologyEntities = ontologyNodeDao.selectAll();
        ontologyEntities.forEach(ontologyEntity -> {
            OntologyNodeVO oe = new OntologyNodeVO();
            BeanUtils.copyProperties(ontologyEntity, oe);
            SysIcon sysIcon = sysIconMapper.selectByPrimaryKey(ontologyEntity.getIconId());
            oe.setViewUrl(serverConfig.parseViewUrl(sysIcon.getIconFile(), 3));

            oe.setOntologyNodePropertyList(ontologyNodePropertyDao.selectByEntityId(ontologyEntity.getNodeId()));
            ontologyEntityList.add(oe);
        });
        return ontologyEntityList;
    }



    @Override
    public Boolean judgeLabel(Integer type, String labels, Integer entityId) {
        labels = NodeTypeEnum.getNameByCode(type) + "," + labels;
        OntologyNode record = ontologyNodeDao.selectByName(type, labels);
        if (record == null) {
            return false;
        }
        if (entityId != null) {
            return !entityId.equals(record.getNodeId());
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer addOntologyEntityAndProperty(OntologyNodeVO ontologyEntityVO) {
        Integer type = ontologyEntityVO.getType();
        String label = ontologyEntityVO.getLabels();
        String labels = NodeTypeEnum.getNameByCode(type) + "," + label;

        ontologyEntityVO.setLabels(labels);
        ontologyEntityVO.setDeleted(false);
        ontologyEntityVO.setOntologyId(1);
        int result = ontologyNodeDao.insertSelective(ontologyEntityVO);

        //新增实体属性
        List<OntologyNodeProperty> entityPropertyList = ontologyEntityVO.getOntologyNodePropertyList();
        if(!CollectionUtils.isEmpty(entityPropertyList)){
            entityPropertyList.forEach(ontologyEntityProperty -> {
                ontologyEntityProperty.setNodeId(ontologyEntityVO.getNodeId());
                String key = ontologyEntityProperty.getPropertyKey().trim();
                ontologyEntityProperty.setPropertyKey(key);
                ontologyNodePropertyDao.insertSelective(ontologyEntityProperty);
                //主键创建图数据索引
                if (ontologyEntityProperty.getPrimaryKey()) {
                    graphProcessor.createIndex(label, key);
                }
            });
        } else {
            //默认新增两个固定属性
            OntologyNodeProperty entityProperty1 = new OntologyNodeProperty();
            entityProperty1.setNodeId(ontologyEntityVO.getNodeId());
            entityProperty1.setPropertyKey(PROPERTY_NAME);
            entityProperty1.setCount(false);
            entityProperty1.setPrimaryKey(true);
            entityProperty1.setEdit(false);
            ontologyNodePropertyDao.insertSelective(entityProperty1);
            OntologyNodeProperty entityProperty2 = new OntologyNodeProperty();
            entityProperty2.setNodeId(ontologyEntityVO.getNodeId());
            entityProperty2.setPropertyKey(PROPERTY_DESCRIBE);
            entityProperty2.setCount(false);
            entityProperty2.setPrimaryKey(false);
            entityProperty2.setEdit(false);
            ontologyNodePropertyDao.insertSelective(entityProperty2);
            //主键创建图数据索引
            graphProcessor.createIndex(label, PROPERTY_NAME);

            if (type.equals(2)) {
                OntologyNodeProperty entityProperty3 = new OntologyNodeProperty();
                entityProperty3.setNodeId(ontologyEntityVO.getNodeId());
                entityProperty3.setPropertyKey(PROPERTY_STARTTIME);
                entityProperty3.setCount(false);
                entityProperty3.setPrimaryKey(true);
                entityProperty3.setEdit(false);
                ontologyNodePropertyDao.insertSelective(entityProperty3);
                OntologyNodeProperty entityProperty4 = new OntologyNodeProperty();
                entityProperty4.setNodeId(ontologyEntityVO.getNodeId());
                entityProperty4.setPropertyKey(PROPERTY_ENDTIME);
                entityProperty4.setCount(false);
                entityProperty4.setPrimaryKey(false);
                entityProperty4.setEdit(false);
                ontologyNodePropertyDao.insertSelective(entityProperty4);
                OntologyNodeProperty entityProperty5 = new OntologyNodeProperty();
                entityProperty5.setNodeId(ontologyEntityVO.getNodeId());
                entityProperty5.setPropertyKey(PROPERTY_PLACE);
                entityProperty5.setCount(false);
                entityProperty5.setPrimaryKey(false);
                entityProperty5.setEdit(false);
                ontologyNodePropertyDao.insertSelective(entityProperty5);
                //主键创建图数据索引
                graphProcessor.createIndex(label, PROPERTY_STARTTIME);
            }
        }
        //创建图数据索引
        graphProcessor.createIndex(label, GraphDbConstant.PROPERTY_KEY_ID);
        graphProcessor.createIndex(label, GraphDbConstant.PROPERTY_KEY_TASK_ID);

        // 更新全文索引
        fulltextIndexCommon.updateFulltextIndexAll();

        return result;
    }

    @Override
    public Integer updateEntity(Integer entityId, String content, Integer iconId, Integer updateType) {
        OntologyNode ontologyNode = ontologyNodeDao.selectByPrimaryKey(entityId);
        if (updateType.equals(0)) {
            String prefix = StringUtils.substringBeforeLast(ontologyNode.getLabels(), ",");
            ontologyNode.setLabels(prefix + "," + content);

            //创建图数据索引,主键索引
            List<OntologyNodeProperty> ontologyEntityProperties = ontologyNodePropertyDao.selectByEntityId(entityId);
            ontologyEntityProperties.forEach(prop -> {
                if (prop.getPrimaryKey()) {
                    graphProcessor.createIndex(content, prop.getPropertyKey());
                }
            });

            //创建图数据索引,其他固定属性索引
            graphProcessor.createIndex(content, GraphDbConstant.PROPERTY_KEY_ID);
            graphProcessor.createIndex(content, GraphDbConstant.PROPERTY_KEY_TASK_ID);
            // 更新全文索引
            fulltextIndexCommon.updateFulltextIndexAll();
        } else {
            ontologyNode.setIconId(iconId);
        }
        return ontologyNodeDao.updateByPrimaryKeySelective(ontologyNode);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer deleteEntity(Integer entityId) {
        //删除子级节点
        List<OntologyNode> ontologyNodes = ontologyNodeDao.selectChildrenNodes(entityId);
        ontologyNodes.forEach(ontologyNode -> deleteEntity(ontologyNode.getNodeId()));

        //删除相关边的绑定
//        ontologyRelationshipMapper.deleteByEntityId(entityId);
        //删除相关的图标和属性
//        ontologyNodePropertyDao.deleteByEntityId(entityId);
        return ontologyNodeDao.updateEntityByDelete(entityId);
    }

    @Override
    public OntologyNodeVO getOntologyEntityVO(Integer entityId) {
        OntologyNodeVO OntologyNodeVO = new OntologyNodeVO();
        OntologyNode ontologyNode = ontologyNodeDao.selectByPrimaryKey(entityId);
        List<OntologyNodeProperty> ontologyEntityProperties = ontologyNodePropertyDao.selectByEntityId(entityId);
        OntologyNodeVO.setOntologyNodePropertyList(ontologyEntityProperties);
        ontologyNode.setLabels(StringUtils.substringAfterLast(ontologyNode.getLabels(), ","));
        SysIcon sysIcon = sysIconMapper.selectByPrimaryKey(ontologyNode.getIconId());
        String viewUrl = serverConfig.parseViewUrl(sysIcon.getIconFile(), 3);
        OntologyNodeVO.setViewUrl(viewUrl);
        BeanUtils.copyProperties(ontologyNode, OntologyNodeVO);
        return OntologyNodeVO;
    }

    @Override
    public List<NodeListVO> getOntologyEntityList(Integer type) {
        List<NodeListVO> nodes = new ArrayList<>();
        List<OntologyNode> ontologyEntities = ontologyNodeDao.selectByType(type);
        ontologyEntities.forEach(ontologyEntity -> {
            NodeListVO ontologyNode = new NodeListVO();
            String suffix = StringUtils.substringAfterLast(ontologyEntity.getLabels(), ",");
            ontologyNode.setLabels(suffix);
            ontologyNode.setNodeId(ontologyEntity.getNodeId());
            ontologyNode.setType(type);
            List<NodeRelationshipVO> nodeRelationships = ontologyRelationshipMapper.selectRelationshipVOs(ontologyEntity.getNodeId());
            ontologyNode.setRelation(!CollectionUtils.isEmpty(nodeRelationships));
            ontologyNode.setId(ontologyEntity.getNodeId().toString());
            ontologyNode.setParentId(ontologyEntity.getParentId().toString());
            nodes.add(ontologyNode);
        });

        return TreeUtil.build(nodes, "0");
    }

    @Override
    public Boolean judgePropertyKey(Integer nodeId, String propertyKey, Integer propertyId) {
        OntologyNodeProperty record = ontologyNodePropertyDao.selectByPropertyKey(nodeId, propertyKey);
        if (record == null) {
            return false;
        }
        if (propertyId != null) {
            return !propertyId.equals(record.getPropertyId());
        }
        return true;
    }

    @Override
    public Integer addEntityProperty(OntologyNodeProperty ontologyNodeProperty) {
        return ontologyNodePropertyDao.insertSelective(ontologyNodeProperty);
    }

    @Override
    public Integer updateEntityProperty(OntologyNodeProperty ontologyNodeProperty) {
        return ontologyNodePropertyDao.updateByPrimaryKeySelective(ontologyNodeProperty);
    }

    @Override
    public Integer deleteEntityProperty(Integer propertyId) {
        return ontologyNodePropertyDao.deleteByPrimaryKey(propertyId);
    }

    @Override
    public List<OntologyNode> listSecondEntities() {
        List<OntologyNode> records = ontologyNodeDao.selectAll();
        records.forEach(ontologyEntity ->
                ontologyEntity.setLabels(StringUtils.substringAfterLast(ontologyEntity.getLabels(), ",")));
        return records;
    }

    @Override
    public Boolean judgeRelationship(OntologyRelationship relationship) {
        OntologyRelationship record = ontologyRelationshipMapper.selectSameRelationship(relationship);
        if (record == null) {
            return false;
        }
        if (relationship.getRelationshipId() != null) {
            return !relationship.getRelationshipId().equals(record.getRelationshipId());
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer addRelationship(OntologyRelationshipVO ontologyRelationshipVO) {
        ontologyRelationshipVO.setOntologyId(1);
        int result = ontologyRelationshipMapper.insertSelective(ontologyRelationshipVO);

        List<OntologyRelationshipProperty> relationshipPropertyList = ontologyRelationshipVO.getOntologyRelationshipPropertyList();
        if (!CollectionUtils.isEmpty(relationshipPropertyList)) {
            relationshipPropertyList.forEach(relationshipProperty -> {
                relationshipProperty.setRelationshipId(ontologyRelationshipVO.getRelationshipId());
                String key = relationshipProperty.getPropertyKey().trim();
                relationshipProperty.setPropertyKey(key);
                ontologyRelationshipPropertyMapper.insertSelective(relationshipProperty);
            });
        } else {
            //默认新增两个固定属性
            OntologyRelationshipProperty relationshipProperty1 = new OntologyRelationshipProperty();
            relationshipProperty1.setRelationshipId(ontologyRelationshipVO.getRelationshipId());
            relationshipProperty1.setPropertyKey(PROPERTY_NAME);
            relationshipProperty1.setCount(false);
            relationshipProperty1.setPrimaryKey(false);
            relationshipProperty1.setEdit(false);
            ontologyRelationshipPropertyMapper.insertSelective(relationshipProperty1);
            OntologyRelationshipProperty relationshipProperty2 = new OntologyRelationshipProperty();
            relationshipProperty2.setRelationshipId(ontologyRelationshipVO.getRelationshipId());
            relationshipProperty2.setPropertyKey(PROPERTY_DESCRIBE);
            relationshipProperty2.setCount(false);
            relationshipProperty2.setPrimaryKey(false);
            relationshipProperty2.setEdit(false);
            ontologyRelationshipPropertyMapper.insertSelective(relationshipProperty2);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updateRelationship(OntologyRelationshipVO ontologyRelationshipVO) {
        ontologyRelationshipVO.setOntologyId(1);
        int result = ontologyRelationshipMapper.updateByPrimaryKeySelective(ontologyRelationshipVO);

        ontologyRelationshipPropertyMapper.deleteByRelationshipId(ontologyRelationshipVO.getRelationshipId());
        List<OntologyRelationshipProperty> relationshipPropertyList = ontologyRelationshipVO.getOntologyRelationshipPropertyList();
        if (!CollectionUtils.isEmpty(relationshipPropertyList)) {
            relationshipPropertyList.forEach(relationshipProperty -> {
                String key = relationshipProperty.getPropertyKey().trim();
                relationshipProperty.setPropertyKey(key);
                ontologyRelationshipPropertyMapper.insertSelective(relationshipProperty);
            });
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer deleteRelationship(Integer relationshipId) {
        ontologyRelationshipPropertyMapper.deleteByRelationshipId(relationshipId);
        return ontologyRelationshipMapper.deleteByPrimaryKey(relationshipId);
    }

    @Override
    public RelationshipBindVO getEntityRelationshipVOs(Integer entityId) {
        RelationshipBindVO relationshipBindVO = new RelationshipBindVO();
        List<GraphNeo4jVO.Node> nodes = new ArrayList<>();
        List<GraphNeo4jVO.Link> links = new ArrayList<>();

        List<NodeRelationshipVO> nodeRelationshipVOS = ontologyRelationshipMapper.selectRelationshipVOs(entityId);
        nodeRelationshipVOS.forEach(nodeRelationshipVO -> {
            GraphNeo4jVO.Node startEntity = new GraphNeo4jVO.Node();
            String startNodeName = nodeRelationshipVO.getStartNodeName();
            startEntity.setName(StringUtils.substringAfterLast(startNodeName, ","));
            startEntity.setId(nodeRelationshipVO.getStartNodeId().toString());
            SysIcon startIcon = sysIconMapper.selectByPrimaryKey(nodeRelationshipVO.getStartIconId());
            startEntity.setIcon(serverConfig.parseViewUrl(startIcon.getIconFile(), 3));
            nodes.add(startEntity);

            GraphNeo4jVO.Node endEntity = new GraphNeo4jVO.Node();
            String endNodeName = nodeRelationshipVO.getEndNodeName();
            endEntity.setName(StringUtils.substringAfterLast(endNodeName, ","));
            endEntity.setId(nodeRelationshipVO.getEndNodeId().toString());
            SysIcon endIcon = sysIconMapper.selectByPrimaryKey(nodeRelationshipVO.getEndIconId());
            endEntity.setIcon(serverConfig.parseViewUrl(endIcon.getIconFile(), 3));
            nodes.add(endEntity);

            GraphNeo4jVO.Link link = new GraphNeo4jVO.Link();
            link.setId(nodeRelationshipVO.getRelationshipId().toString());
            link.setStartNodeId(startEntity.getId());
            link.setEndNodeId(endEntity.getId());
            link.setType(nodeRelationshipVO.getType());
            links.add(link);
        });
        relationshipBindVO.setGraph(new GraphNeo4jVO(nodes, links));
        return relationshipBindVO;

    }

    @Override
    public List<NodeRelationshipVO> selectEntityRelationshipVOs(Integer currentId, Integer selectId) {
        List<NodeRelationshipVO> nodeRelationshipVOS = ontologyRelationshipMapper.selectRelationshipVOsByIds(currentId, selectId);
        nodeRelationshipVOS.forEach(nodeRelationshipVO -> {
            String startNodeName = nodeRelationshipVO.getStartNodeName();
            nodeRelationshipVO.setStartNodeName(StringUtils.substringAfterLast(startNodeName, ","));
            String endNodeName = nodeRelationshipVO.getEndNodeName();
            nodeRelationshipVO.setEndNodeName(StringUtils.substringAfterLast(endNodeName, ","));
        });
        return nodeRelationshipVOS;
    }

    @Override
    public NodeRelationshipVO selectEntityRelationshipById(Integer relationshipId) {
        NodeRelationshipVO nodeRelationshipVO = ontologyRelationshipMapper.selectRelationshipById(relationshipId);
        String startNodeName = nodeRelationshipVO.getStartNodeName();
        nodeRelationshipVO.setStartNodeName(StringUtils.substringAfterLast(startNodeName, ","));
        String endNodeName = nodeRelationshipVO.getEndNodeName();
        nodeRelationshipVO.setEndNodeName(StringUtils.substringAfterLast(endNodeName, ","));
        return nodeRelationshipVO;
    }


    @Override
    public Integer deleteRelationshipProperty(Integer propertyId) {
        return ontologyRelationshipPropertyMapper.deleteByPrimaryKey(propertyId);
    }

    @Override
    public Boolean judgeRelationshipKey(Integer propertyId, String propertyKey, Integer relationshipId) {
        OntologyRelationshipProperty record = ontologyRelationshipPropertyMapper.selectSameKey(propertyKey, relationshipId);
        if (record == null) {
            return false;
        }
        if (propertyId != null) {
            return !propertyId.equals(record.getPropertyId());
        }
        return true;
    }

    @Override
    public RelationshipVO getRelationship(Integer relationshipId, Integer currentId) {
        RelationshipVO ontologyRelationshipVO = new RelationshipVO();
        OntologyRelationship ontologyRelationship = ontologyRelationshipMapper.selectByPrimaryKey(relationshipId);
        List<OntologyRelationshipProperty> ontologyRelationshipProperties = ontologyRelationshipPropertyMapper.selectByRelationshipId(relationshipId);
        ontologyRelationshipVO.setOntologyRelationshipPropertyList(ontologyRelationshipProperties);
        BeanUtils.copyProperties(ontologyRelationship, ontologyRelationshipVO);
        ontologyRelationshipVO.setDirection(ontologyRelationship.getStartNodeId().equals(currentId));

        return ontologyRelationshipVO;
    }


    @Override
    public Integer addRelationshipProperty(OntologyRelationshipProperty ontologyRelationshipProperty) {
        return ontologyRelationshipPropertyMapper.insertSelective(ontologyRelationshipProperty);
    }

    @Override
    public Integer updateRelationshipProperty(OntologyRelationshipProperty ontologyRelationshipProperty) {
        return ontologyRelationshipPropertyMapper.updateByPrimaryKeySelective(ontologyRelationshipProperty);
    }


//    @Override
//    public List<CountPropertyKeyVO> listCountPropertyKeyByLabels(String[] labels) {
//        List<CountPropertyKeyVO> retValue = new ArrayList<>();
//        for (String label : labels) {
//            CountPropertyKeyVO countPropertyKey = new CountPropertyKeyVO();
//            countPropertyKey.setLabel(label);
//            countPropertyKey.setPropertyKeys(ontologyEntityPropertyMapper.listCountPropertyKeyByLabel(label));
//            retValue.add(countPropertyKey);
//        }
//        return retValue;
//    }


    @Override
    public List<RelationshipAndPropertyVO> listRelationshipByLabels(String startLabels, String endLabels) {
        List<RelationshipAndPropertyVO> retValue  = ontologyRelationshipMapper.listRelationshipByLabels(startLabels, endLabels);
        retValue.forEach(rel -> rel.setRelationshipProperties(ontologyRelationshipPropertyMapper
                        .selectByRelationshipId(rel.getRelationshipId())));
        return retValue;
    }

}
